/**
  ******************************************************************************
  * @file    Hourmeter.c
  * @author  Dajin Li
  * @version V0.0.1
  * @date    08-08-2015 
  * @brief   This file contains functions/task to update/save the hourmeters
  *          
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; KION(SZ) R&D Center
  *
  * Licensed under KION, (the "License");
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/

#include "stm32f10x.h"
#include "global.h"
#include "hourmeter.h"
#include "var_tbl.h"
#include "switch.h"
#include "menu.h"
#include "icons.h"


HourMtr_TypeDef	Hrm_Struct;
union CLEAR_SCREEN_FLAGS ClearScreenFlags = {0};
u8 PreMatinFlag = 0;
u8 MatinInfoScreen = 0;

/**
* @brief	Increment_HourmeterValue
* @param	none
* @note     none
* @retval   none
*/
u32 Increment_HourmeterValue(u32 hrm_value)
{
    hrm_value++;
    if (hrm_value > HRM_MAX) //99999.9
    {
        ClearHrmOnce = 1;
        hrm_value = 0;  // roll to 0
    }
    return (hrm_value);
}
/**
* @brief	Increment keyon hourmeter
* @param	none
* @note     none
* @retval   none
*/
void Inc_Keyon_HM (void)
{
    Hrm_Struct.HM1_prescaler++;
    if (Hrm_Struct.HM1_prescaler >= HRM_PRESC_MAX)  // key on hourmeter
	{
        Hrm_Struct.HM1_prescaler = 0; 
        Hrm_Struct.HM1_value = Increment_HourmeterValue(Hrm_Struct.HM1_value);
    } 
    WriteBackupRegister(HM1_BK_ADRESS, Hrm_Struct.HM1_prescaler);
//    RTC_WriteBackupRegister(RTC_BKP_DR1, Hrm_Struct.HM1_prescaler);
}
/**
* @brief	Increment lift hourmeter
* @param	none
* @note     none
* @retval   none
*/
void Inc_Lift_HM (void)
{
    if(BR1189_lift_status.hourmeter_counter_flag == HM_COUNTER_OFF)
    {
        return;
    }
    Hrm_Struct.HM2_prescaler++;
    if (Hrm_Struct.HM2_prescaler >= HRM_PRESC_MAX)  // key on hourmeter
	{
        Hrm_Struct.HM2_prescaler = 0;
        Hrm_Struct.HM2_value = Increment_HourmeterValue(Hrm_Struct.HM2_value);
    }  
    WriteBackupRegister(HM2_BK_ADRESS, Hrm_Struct.HM2_prescaler);
//    RTC_WriteBackupRegister(RTC_BKP_DR1, Hrm_Struct.HM1_prescaler);
}

/**
* @brief	Increment lift hourmeter
* @param	none
* @note     none
* @retval   none
*/
void Inc_Trac_HM (void)
{
    if(BR1189_trac_status.hourmeter_counter_flag == HM_COUNTER_OFF)
    {
        return;
    }
    Hrm_Struct.HM3_prescaler++;
    if (Hrm_Struct.HM3_prescaler >= HRM_PRESC_MAX)  // key on hourmeter
	{
        Hrm_Struct.HM3_prescaler = 0;
        Hrm_Struct.HM3_value = Increment_HourmeterValue(Hrm_Struct.HM3_value);
    }  
    WriteBackupRegister(HM3_BK_ADRESS, Hrm_Struct.HM3_prescaler);
//    RTC_WriteBackupRegister(RTC_BKP_DR1, Hrm_Struct.HM1_prescaler);
}
/**
* @brief	Increment lift hourmeter
* @param	none
* @note     none
* @retval   none
*/
void Inc_Steer_HM (void)
{
    if(BR1189_steer_status.hourmeter_counter_flag == HM_COUNTER_OFF)
    {
        return;
    }
    Hrm_Struct.HM4_prescaler++;
    if (Hrm_Struct.HM4_prescaler >= HRM_PRESC_MAX)  // key on hourmeter
	{
        Hrm_Struct.HM4_prescaler = 0;
        Hrm_Struct.HM4_value = Increment_HourmeterValue(Hrm_Struct.HM4_value);
    }  
    WriteBackupRegister(HM4_BK_ADRESS, Hrm_Struct.HM4_prescaler);
//    RTC_WriteBackupRegister(RTC_BKP_DR1, Hrm_Struct.HM1_prescaler);
}
/**
* @brief	Decrement_MaintMon1
* @param	none
* @note     none
* @retval   none
*/
void Decrement_Maint_Eng_Oil(void)
{
    Hrm_Struct.prescaler1--;
    
    if (Hrm_Struct.prescaler1 <= 0)	
    {
        Hrm_Struct.prescaler1 = HRM_PRESC_MAX * 10;
        Hrm_Struct.Service_hours1--;
        if(Hrm_Struct.Service_hours1 < -999)
        {
			Hrm_Struct.Service_hours1 = -999;
        }
        service_hours1 = Hrm_Struct.Service_hours1;
    }
//    RTC_WriteBackupRegister(RTC_BKP_DR3, Hrm_Struct.prescaler1);
}
/**
* @brief	Decrement_MaintMon2
* @param	none
* @note     none
* @retval   none
*/
void Decrement_Maint_Air_Filter(void)
{
    Hrm_Struct.prescaler2--;
	if (Hrm_Struct.prescaler2 <= 0)	
    {
		Hrm_Struct.prescaler2 = HRM_PRESC_MAX * 10;
		Hrm_Struct.Service_hours2--;
        if(Hrm_Struct.Service_hours2 < -999)
        {
			Hrm_Struct.Service_hours2 = -999;
        }
        
        service_hours2 = Hrm_Struct.Service_hours2;
    }
//    RTC_WriteBackupRegister(RTC_BKP_DR4, Hrm_Struct.prescaler2);
}
/**
* @brief	Decrement_MaintMon3
* @param	none
* @note     none
* @retval   none
*/
void Decrement_Maint_Service_Eng(void)
{
	Hrm_Struct.prescaler3--;
	if (Hrm_Struct.prescaler3 <= 0)
    {	
		Hrm_Struct.prescaler3 = HRM_PRESC_MAX * 10;
		Hrm_Struct.Service_hours3--;
        if(Hrm_Struct.Service_hours3 < -999)
        {
			Hrm_Struct.Service_hours3 = -999;
        }
        
        service_hours3 = Hrm_Struct.Service_hours3;
    }
//    RTC_WriteBackupRegister(RTC_BKP_DR5, Hrm_Struct.prescaler3);
}
/**
* @brief	Decrement_MaintMon3
* @param	none
* @note     none
* @retval   none
*/
void Decrement_Maint_Service_Machine(void)
{
	Hrm_Struct.prescaler4--;
	if(Hrm_Struct.prescaler4 <= 0)
    {	
		Hrm_Struct.prescaler4 = HRM_PRESC_MAX * 10;
		Hrm_Struct.Service_hours4--;
        if(Hrm_Struct.Service_hours4 < -999)
        {
			Hrm_Struct.Service_hours4 = -999;
        }
        service_hours4 = Hrm_Struct.Service_hours4;
    }
//    RTC_WriteBackupRegister(RTC_BKP_DR6, Hrm_Struct.prescaler4);
}

static void test_maint(void)
{
    if(Hrm_Struct.Service_hours3 <= 0 || Hrm_Struct.Service_hours4 <= 0)
    {
        fault_status |= MAINT_FAULT;
    }
    else if (Hrm_Struct.Service_days3 <= 0 || Hrm_Struct.Service_days4 <= 0)
    {
        fault_status |= MAINT_FAULT;
    }
    else 
    {
        fault_status &= ~MAINT_FAULT;
    }
}


static void inc_hourmeter(void)
{
    Inc_Keyon_HM();
    Inc_Lift_HM();
    Inc_Trac_HM();
    Inc_Steer_HM();
}
static void dec_maint_hours(void)
{
    Decrement_Maint_Eng_Oil();
    Decrement_Maint_Air_Filter();
    Decrement_Maint_Service_Eng();
    Decrement_Maint_Service_Machine();
}

static void dec_maint_days(void)
{
    s16 day_offset;
    if(Hrm_Struct.day != date_day)
    {
        if(Hrm_Struct.day < date_day) // cross day
        {
            day_offset = date_day - Hrm_Struct.day;
            Hrm_Struct.day = date_day;
//            RTC_WriteBackupRegister(RTC_BKP_DR8, Hrm_Struct.day);
        }
        else // cross month
        {
            if(Hrm_Struct.month == 2)
            {
                if(((date_year%4== 0) && (date_year%100!= 0)) || (date_year % 400 == 0)) // leap year
                {
                    day_offset = date_day + 29 - Hrm_Struct.day;
                }
                else
                {
                    day_offset = date_day + 28 - Hrm_Struct.day;
                }
            }
            else if(Hrm_Struct.month == 4 || Hrm_Struct.month == 6 || Hrm_Struct.month == 9 || Hrm_Struct.month == 11) // 30 days
            {
                day_offset = date_day + 30 - Hrm_Struct.day;
            }
            else // 31 days
            {
                day_offset = date_day + 31 - Hrm_Struct.day;
            }
            Hrm_Struct.day = date_day;
//            RTC_WriteBackupRegister(RTC_BKP_DR8, Hrm_Struct.day);

            Hrm_Struct.month = date_month;
//            RTC_WriteBackupRegister(RTC_BKP_DR7, Hrm_Struct.month);
        }

        Hrm_Struct.Service_days1 -= day_offset;
        Hrm_Struct.Service_days2 -= day_offset;
        Hrm_Struct.Service_days3 -= day_offset;
        Hrm_Struct.Service_days4 -= day_offset;

        if (Hrm_Struct.Service_days1 < -99)
        {
            Hrm_Struct.Service_days1 = -99;
        }
        if (Hrm_Struct.Service_days2 < -99)
        {
            Hrm_Struct.Service_days2 = -99;
        }
        if (Hrm_Struct.Service_days3 < -99)
        {
            Hrm_Struct.Service_days3 = -99;
        }  
        if (Hrm_Struct.Service_days4 < -99)
        {
            Hrm_Struct.Service_days4 = -99;
        }            

        service_days3 = Hrm_Struct.Service_days3;
        service_days4 = Hrm_Struct.Service_days4;
        service_days2 = Hrm_Struct.Service_days2;
        service_days1 = Hrm_Struct.Service_days1;
    }
}



/**
* @brief	This task updates the hourmeters and maintenance monitors.
* @param	void const *argument
* @note     none
* @retval   none
*/
void hourmeters_task(void const *argument) 
{
    // Initialization 
    task_status[UPDT_HRMTRS_ID] = ALIVE;
    
    Hrm_Struct.HM1_prescaler = ReadBackupRegister(HM1_BK_ADRESS);
    Hrm_Struct.HM2_prescaler = ReadBackupRegister(HM2_BK_ADRESS);
    Hrm_Struct.HM3_prescaler = ReadBackupRegister(HM3_BK_ADRESS);
    Hrm_Struct.HM4_prescaler = ReadBackupRegister(HM4_BK_ADRESS);    
//    Hrm_Struct.prescaler1 = RTC_ReadBackupRegister(RTC_BKP_DR3);
//    Hrm_Struct.prescaler2 = RTC_ReadBackupRegister(RTC_BKP_DR4);
//    Hrm_Struct.prescaler3 = RTC_ReadBackupRegister(RTC_BKP_DR5);
//    Hrm_Struct.prescaler4 = RTC_ReadBackupRegister(RTC_BKP_DR6);
//    Hrm_Struct.month = RTC_ReadBackupRegister(RTC_BKP_DR7);

    if(Hrm_Struct.month == 0 || Hrm_Struct.month > 12)
    {
        Hrm_Struct.month = date_month;
//        RTC_WriteBackupRegister(RTC_BKP_DR7, Hrm_Struct.month);
    }
        
//    Hrm_Struct.day = RTC_ReadBackupRegister(RTC_BKP_DR8);
//    if(Hrm_Struct.day == 0 || Hrm_Struct.day > 31)
//    {
//        Hrm_Struct.day = date_day;
//        RTC_WriteBackupRegister(RTC_BKP_DR8, Hrm_Struct.day);
//    }

    // Tasks must run in an infinite loop:
    while (TRUE)
    {
        inc_hourmeter();  
        dec_maint_hours();
        dec_maint_days();
        test_maint();
        check_matin_hour();
        task_status[UPDT_HRMTRS_ID] = ALIVE;
        osDelay(UPDT_HRMTRS_ITV);
    }  // end while infinite loop
}  // end hourmeters_task() 

/**
* @brief	Store key var to backup register.
* @param	BK_Address: Back up register remap address
            Data: 32Bit data
* @note     none
* @retval   if store sucess, return 1, else return 0
*/
u8 WriteBackupRegister(U16 BK_Address, U32 Data)
{
    U32 Read_Back;
    BKP_WriteBackupRegister((BK_Address - 1) * 4, Data);
    BKP_WriteBackupRegister((BK_Address) * 4, Data >> 16);
    Read_Back =  BKP_ReadBackupRegister(BK_Address * 4) << 16 | BKP_ReadBackupRegister((BK_Address - 1) * 4);   //After store, read it back to check if the data is stored
    if(Read_Back == Data)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}// end WriteBackupRegister

u32 ReadBackupRegister(U16 BK_Address)
{
    U32 Read_Back;
    Read_Back =  BKP_ReadBackupRegister(BK_Address * 4) << 16 | BKP_ReadBackupRegister((BK_Address - 1) * 4);
    return Read_Back;
}

void check_matin_hour(void)
{
    if(ServiceByHours - Hrm_Struct.HM3_value <= ServicePresetHours)
    {
        PreMatinFlag = 1;
    }
    else
    {
        PreMatinFlag = 0;
    }
    if(Hrm_Struct.HM3_value >= ServiceByHours )
    {
        MatinInfoScreen = 1;
    }
    else
    {
        MatinInfoScreen = 0;
    }
}
